//
//  NSSet+ZXAvoidCrash.m
//  ZXAvoidCrash
//
//  Created by 朱新明 on 2023/3/21.
//  

#import "NSSet+ZXAvoidCrash.h"
#import "ZXAvoidCrashRuntime.h"
#import "ZXAvoidCrashReport.h"

@implementation NSSet (ZXAvoidCrash)



+ (void)zx_avoidCrashExchangeMethod
{ 
    //NSSet和NSMutableSet的占位对象：instance method 和 类方法同一个;alloc创建的对象。
    Class __NSPlaceholderSet = NSClassFromString(@"__NSPlaceholderSet");
    
    [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:__NSPlaceholderSet originalSelector:@selector(initWithObjects:count:) swizzledSelector:@selector(zx_avoidCrashInitWithObjects:count:)];
    
    Class NSSet = NSClassFromString(@"NSSet");
    [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:NSSet originalSelector:@selector(setByAddingObject:) swizzledSelector:@selector(zx_avoidCrashSetByAddingObject:)];
}


#pragma mark- 初始化

//=================================================================
/*
 __NSPlaceholderSet
*  - (instancetype)initWithObjects:(const ObjectType _Nonnull [_Nullable])objects count:(NSUInteger)cnt 
* + (instancetype)setWithObject:(ObjectType)object;
 */
//=================================================================
/*
 崩溃：
 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderSet initWithObjects:count:]: attempt to insert nil object from objects[0]'
objects肯定不为NULL，是一个指针，objects内部元素有nil时会崩溃。内部如果cnt数量大于真实objects数量也返回nil。
 例如：
 id obj = nil;
 id objects[] = {obj, @"Hello, World!", @42};
 NSSet *set = [NSSet setWithObjects:objects count:3];
 */

- (instancetype)zx_avoidCrashInitWithObjects:(const id _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt
{
    id instance = nil;
    @try {
        instance =  [self zx_avoidCrashInitWithObjects:objects count:cnt];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception];
    } @finally {
        return instance;
    }
}



//=================================================================
/*
 __NSSetI
*  - (NSSet<ObjectType> *)setByAddingObject:(ObjectType)anObject;
 */
//=================================================================
/*
 崩溃：
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSSet setByAddingObject:]: object cannot be nil'
 例如：
 NSSet *set = [NSSet set];
 [set setByAddingObject:nil];
 */

- (NSSet<id> *)zx_avoidCrashSetByAddingObject:(id)anObject{
    id instance = self;
    @try {
        instance =  [self zx_avoidCrashSetByAddingObject:anObject];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception];
    } @finally {
        return instance;
    }
}

@end

